import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.jgrapht.alg.ConnectivityInspector;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;
import org.jgrapht.graph.UndirectedWeightedSubgraph;

/**
 * A manipulator that removes from an annotated cluster any gene that is not annotated with the
 * main annotation and is not essential to the cluster's connectivity.
 * Clusters without a dominant annotation are also removed.
 * @author odedmagg
 *
 */
public class CLMEnrichmentLegalizer implements ClusterListManipulator {
	private AnnotationsManager _annotMgr;
	private SimpleWeightedGraph<String, DefaultWeightedEdge> _graph;
	
	public CLMEnrichmentLegalizer(AnnotationsManager a, 
			SimpleWeightedGraph<String, DefaultWeightedEdge> graph) {
		_annotMgr = a;
		_graph       = graph;
	}
	
	public void manipulate(List<Cluster> clusters) {
		// Sanity check
		if ((_annotMgr == null) || (_graph == null))
			return;
		
		Iterator<Cluster> citer = clusters.iterator();
		while (citer.hasNext()) {
			Cluster c = citer.next();
			
			// Remove the cluster if it is not annotated.
			if (!c.isAnnotated()) {
				citer.remove();
				continue;
			}
			
			Iterator<Gene> giter = c.iterator();
			HashSet<String> vertices = c.memberNames(); // will remained synched with current vertices of the cluster - 
																					// programmer's responsibility.
			while (giter.hasNext()) {
				Gene g = giter.next();
				if (!_annotMgr.isGeneAnnotated(g, c.getAnnotation())) {
					String suspectGene = g.getName();
					vertices.remove(suspectGene);
					
					// Check connectability
					UndirectedWeightedSubgraph<String, DefaultWeightedEdge> subgraph = 
						new UndirectedWeightedSubgraph<String, DefaultWeightedEdge>(getGraph(), vertices, null);
							
					ConnectivityInspector<String, DefaultWeightedEdge> connectivityInspector = 
						new ConnectivityInspector<String, DefaultWeightedEdge>(subgraph);
					
					if (connectivityInspector.isGraphConnected()) {
						// Workaround  - remove gene (not essential to connectivity).
						giter.remove();
						g.removeCluster(c);
					}
					else {
						// Keep the gene.
						vertices.add(suspectGene); 
					}
				}
				
			}
		}
	}

	public void setAnnotMgr(AnnotationsManager annotMgr) {
		this._annotMgr = annotMgr;
	}

	public AnnotationsManager getAnnotMgr() {
		return _annotMgr;
	}

	public void setGraph(SimpleWeightedGraph<String, DefaultWeightedEdge> graph) {
		this._graph = graph;
	}

	public SimpleWeightedGraph<String, DefaultWeightedEdge> getGraph() {
		return _graph;
	}

}
